/**
 * 
 */
package snucse.teamd;

import java.awt.Button;
import java.awt.Color;
import java.awt.FileDialog;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;

import snucse.teamd.math.MyMath;
import snucse.teamd.math.Vec2;

import com.jogamp.opengl.util.FPSAnimator;
import com.jogamp.opengl.util.awt.TextRenderer;

//import snucse.teamd.math.*;

/**
 * @author k2d2o2
 * 
 */
public class UIController {

	/**
	 * This's working on macosx now
	 * 
	 * @param args
	 */
	static private final int WINDOW_HEIGHT = 600;
	private double theta = 0;
	private double s = 0;
	private double c = 0;
	private long lastFrameTime;
	private long elapsedTime;
	private double frameRate;
	private World world;
	private TempBody tempBody;
	private boolean isGenerateMode;
	private boolean isFreeDrawMode;
	private UIListener listener;
	private Label fpsLabel ;
	private ArrayList<Double> storedFrameRate;
	private HashMap<String, TextField> bodyParamTexts;
	private TextRenderer textRenderer;
	
	private ArrayList<Label> propertyLabels; 
	private Body selectedBody;
	
	final private String[] bodyParamNames = { "vertNum", "rotAngle", "mass",
			"coeOfFric", "coeOfRest", "linearVelX", "linearVelY", "angularVel",
			"vertices" };

	public UIController(World w) {
		this.world = w;
		setGenerateMode(false);
		setFreeDrawMode(false);
		elapsedTime = 0;
		tempBody = null;
		lastFrameTime = System.currentTimeMillis();
		storedFrameRate = new ArrayList<Double>();
		selectedBody = null;
		propertyLabels = new ArrayList<Label>();
		//textRenderer = new TextRenderer(new Font("Monospaced", Font.PLAIN, 12));
		//textRenderer.setColor(Color.WHITE);
		
		int windowOffsetY = 22;
		int frameW = 1000;
		int frameH = 600 + windowOffsetY;

		int canvasX = 0;
		int canvasY = 0;
		int canvasW = 800;
		int canvasH = 600;

		int panelW = (frameW - canvasW);
		int panelH = canvasH;

		final Frame frame = new Frame("Tiny Physics Engine");
		frame.setSize(frameW, frameH);
		frame.setLayout(null);

		GLProfile glp = GLProfile.getDefault();
		GLCapabilities caps = new GLCapabilities(glp);
		GLCanvas canvas = new GLCanvas(caps);
		canvas.setBounds(canvasX, canvasY, canvasW, canvasH);
		canvas.setLocation(0, windowOffsetY);
		Panel menuPanel;
		menuPanel = new Panel();
		menuPanel.setSize(panelW, panelH);
		menuPanel.setLocation(canvasW, windowOffsetY);
		menuPanel.setLayout(null);

		int initOffsetY = 10;
		int initOffsetX = 10;

		int buttonPosY = initOffsetY;

		int buttonW = panelW / 2 - initOffsetX;
		int buttonH = 20;
		int buttonGap = initOffsetX / 2;

		// /// LOAD & SAVE BUTTON////////////
		Button loadButton, saveButton;
		loadButton = new Button("Load");
		loadButton.setBounds(initOffsetX, buttonPosY, buttonW, buttonH);

		saveButton = new Button("Save");
		saveButton.setBounds(initOffsetX + buttonGap + buttonW, buttonPosY,
				buttonW, buttonH);

		// ///// PLAY, PAUSE & CLEAR Button //////
		Button playButton, pauseButton, clearButton;
		buttonPosY += buttonH + buttonGap;

		playButton = new Button("Play");
		playButton.setBounds(initOffsetX, buttonPosY, buttonW / 2, buttonH);

		pauseButton = new Button("Pause");
		pauseButton.setBounds(initOffsetX + (buttonGap + buttonW) / 2,
				buttonPosY, buttonW / 2, buttonH);

		clearButton = new Button("Clear");
		clearButton.setBounds(initOffsetX + buttonW + buttonGap, buttonPosY,
				buttonW, buttonH);
		clearButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				world.reset();
				world.setPlaying(false);
				isGenerateMode = false;

				Vector<Vec2> vertices;
				Body body;
				/* vertices; vertices = new Vector<Vec2>();
				 vertices.addElement(new Vec2(650, 350));
				 vertices.addElement(new Vec2(650, 450));
				 vertices.addElement(new Vec2(750, 450));
				 vertices.addElement(new Vec2(750, 350));  body = new
				 Body(false, (float)Math.PI/6, 30f, new Vec2(-50, 0), (float) Math.PI *
				 0f, 0.2f, 0.7f, (List<Vec2>) vertices);
				 world.addBody(body);
				 
				 vertices = new Vector<Vec2>(); 
				 vertices.addElement(new Vec2(40, 350)); 
				 vertices.addElement(new Vec2(40, 450));
				 vertices.addElement(new Vec2(80, 450));
				 vertices.addElement(new Vec2(80, 350));
				 body = new
				 Body(false, 0f, 30f, new Vec2(50, 0), 0,
						 0.2f, 0.7f, (List<Vec2>) vertices); world.addBody(body);*/
				 /*
				 vertices = new Vector<Vec2>(); vertices.addElement(new
				 Vec2(10, 350)); vertices.addElement(new Vec2(10, 450));
				 vertices.addElement(new Vec2(70, 450));
				 vertices.addElement(new Vec2(130, 350));
				 vertices.addElement(new Vec2(100, 270)); body = new
				 Body(false, 0f, 30f, new Vec2(20, 0), (float) Math.PI * 0.3f,
				 0.2f, 0.5f, (List<Vec2>) vertices); world.addBody(body);
				 
				 vertices = new Vector<Vec2>(); vertices.addElement(new
				 Vec2(410, 450)); vertices.addElement(new Vec2(410, 550));
				 vertices.addElement(new Vec2(470, 550));
				 vertices.addElement(new Vec2(530, 450));
				 vertices.addElement(new Vec2(500, 370)); body = new
				 Body(false, 0f, 30f, new Vec2(0, 0), (float) Math.PI * 0.3f,
				 0.2f, 0.5f, (List<Vec2>) vertices); world.addBody(body); */
				


				//TODO ground_bottom
				 vertices = new Vector<Vec2>(); 
				 vertices.addElement(new Vec2(0, 30)); 
				 vertices.addElement(new Vec2(800, 30));
				 vertices.addElement(new Vec2(800, -800));
				 vertices.addElement(new Vec2(0, -800));
				 body = new
				 Body(true, 0f, 9f, new Vec2(0, 0), 0f,
				 0.08f, 0.1f, (List<Vec2>) vertices); world.addBody(body);
				 
				/*/ground_ceiling
				 vertices = new Vector<Vec2>(); 
				 vertices.addElement(new Vec2(30, 1400));
				 vertices.addElement(new Vec2(770, 1400));
				 vertices.addElement(new Vec2(770, 570));
				 vertices.addElement(new Vec2(30, 570)); 
				 body = new
				 Body(true, 0f, 9f, new Vec2(0, 0), 0f,
				 0.2f, 0.1f, (List<Vec2>) vertices); world.addBody(body);
				 
				 
				 //ground_left
				 vertices = new Vector<Vec2>(); 
				 vertices.addElement(new Vec2(-600, 570));
				 vertices.addElement(new Vec2(30, 570));
				 vertices.addElement(new Vec2(30, 30));
				 vertices.addElement(new Vec2(-600, 30)); 
				 body = new
				 Body(true, 0f, 9f, new Vec2(0, 0), 0f,
				 0.2f, 0.1f, (List<Vec2>) vertices); world.addBody(body);
				 
				 //ground_right
				 vertices = new Vector<Vec2>(); 
				 vertices.addElement(new Vec2(770, 570));
				 vertices.addElement(new Vec2(1400, 570));
				 vertices.addElement(new Vec2(1400, 30));
				 vertices.addElement(new Vec2(770, 30)); 
				 body = new
				 Body(true, 0f, 9f, new Vec2(0, 0), 0f,
				 0.2f, 0.1f, (List<Vec2>) vertices); world.addBody(body);*/
				 
				 
			}
		});

		// /////////////////////////////////////////////////////////////////
		// /////////// Parameters for generating a new body ///////////////
		// ////////////////////////////////////////////////////////////////

		bodyParamTexts = new HashMap<String, TextField>();

		
		
		///////////////////////////////////////////////////////////////////
		Label newBodyLabel = new Label("Add a New Body");
		buttonPosY += buttonH * 2;
		newBodyLabel.setBounds(initOffsetX, buttonPosY, buttonW * 2, buttonH);

		Button freeDrawButton = new Button("Enter Free Drawing Mode");
		buttonPosY += buttonH + buttonGap;
		freeDrawButton.setBounds(initOffsetX, buttonPosY, buttonW * 2
				+ buttonGap, buttonH);

		Label verticesNumLabel = new Label("Vertices Num :");
		TextField verticesNumText = new TextField("5", 3);
		buttonPosY += buttonH + buttonGap;
		verticesNumLabel.setBounds(initOffsetX, buttonPosY, buttonW + 10,
				buttonH);
		verticesNumText.setBounds(initOffsetX + buttonW + buttonW / 2
				+ buttonGap, buttonPosY, buttonW / 2, buttonH);
		bodyParamTexts.put(bodyParamNames[0], verticesNumText);

		Label rotAngleLabel = new Label("Rot. Angle :");
		TextField rotAngleText = new TextField("0.0", 3);
		buttonPosY += buttonH + buttonGap;
		rotAngleLabel.setBounds(initOffsetX, buttonPosY, buttonW, buttonH);
		rotAngleText.setBounds(initOffsetX + buttonW + buttonW / 2 + buttonGap,
				buttonPosY, buttonW / 2, buttonH);
		bodyParamTexts.put(bodyParamNames[1], rotAngleText);

		Label massLabel = new Label("Mass :");
		TextField massText = new TextField("20.0", 3);
		buttonPosY += buttonH + buttonGap;
		massLabel.setBounds(initOffsetX, buttonPosY, buttonW, buttonH);
		massText.setBounds(initOffsetX + buttonW + buttonW / 2 + buttonGap,
				buttonPosY, buttonW / 2, buttonH);
		bodyParamTexts.put(bodyParamNames[2], massText);

		Label coefOfFrictionLabel = new Label("Coef. of Friction:");
		TextField coefOfFrictionText = new TextField("0.9", 3);
		buttonPosY += buttonH + buttonGap;
		coefOfFrictionLabel.setBounds(initOffsetX, buttonPosY, buttonW
				+ buttonW / 2, buttonH);
		coefOfFrictionText.setBounds(initOffsetX + buttonW + buttonW / 2
				+ buttonGap, buttonPosY, buttonW / 2, buttonH);
		bodyParamTexts.put(bodyParamNames[3], coefOfFrictionText);

		Label coefOfRestitutionLabel = new Label("Coef. of Restitution:");
		TextField coefOfRestitutionText = new TextField("0.9", 3);
		buttonPosY += buttonH + buttonGap;
		coefOfRestitutionLabel.setBounds(initOffsetX, buttonPosY, buttonW
				+ buttonW / 2, buttonH);
		coefOfRestitutionText.setBounds(initOffsetX + buttonW + buttonW / 2
				+ buttonGap, buttonPosY, buttonW / 2, buttonH);
		bodyParamTexts.put(bodyParamNames[4], coefOfRestitutionText);

		Label initLienarVelLabel = new Label("Init. Linear Vel (v) : ");
		buttonPosY += buttonH + buttonGap;
		initLienarVelLabel.setBounds(initOffsetX, buttonPosY, buttonW + buttonW
				/ 2, buttonH);

		Label initLinVelXLabel = new Label("x : ");
		Label initLinVelYLabel = new Label("y : ");
		TextField initLinVelXText = new TextField("1", 3);
		TextField initLinVelYText = new TextField("1", 3);
		buttonPosY += buttonH + buttonGap;
		initLinVelXLabel.setBounds(initOffsetX, buttonPosY, buttonW / 3,
				buttonH);
		initLinVelXText.setBounds(initOffsetX + buttonW / 3 + buttonGap,
				buttonPosY, buttonW / 2, buttonH);
		bodyParamTexts.put(bodyParamNames[5], initLinVelXText);
		initLinVelYLabel.setBounds(initOffsetX + buttonW + buttonGap,
				buttonPosY, buttonW / 3, buttonH);
		initLinVelYText.setBounds(initOffsetX + buttonW + buttonW / 3
				+ buttonGap, buttonPosY, buttonW / 2, buttonH);
		bodyParamTexts.put(bodyParamNames[6], initLinVelYText);

		Label initAngVelLabel = new Label("Init. Angular Vel (w) : ");
		TextField initAngVelText = new TextField("1.0", 3);
		buttonPosY += buttonH + buttonGap;
		initAngVelLabel.setBounds(initOffsetX, buttonPosY, buttonW + buttonW
				/ 2, buttonH);
		initAngVelText.setBounds(initOffsetX + buttonW + buttonW / 2
				+ buttonGap, buttonPosY, buttonW / 2, buttonH);
		bodyParamTexts.put(bodyParamNames[7], initAngVelText);

		// //// SHOW, CANCEL & Generate Button////
		Button showButton, cancelButton;
		buttonPosY += buttonH + buttonGap;
		showButton = new Button("Show");
		showButton.setBounds(initOffsetX, buttonPosY, buttonW, buttonH);
		cancelButton = new Button("Cancel");
		cancelButton.setBounds(initOffsetX + buttonGap + buttonW, buttonPosY,
				buttonW, buttonH);
		Button generateButton = new Button("Generate");
		buttonPosY += buttonH + buttonGap;
		generateButton.setBounds(initOffsetX, buttonPosY, buttonW * 2
				+ buttonGap, buttonH);

		/*
		 * 
		 * Environment Setting Parameters
		 */
		Label envLabel = new Label("Environment");
		buttonPosY += buttonH * 2;
		envLabel.setBounds(initOffsetX, buttonPosY, buttonW * 2, buttonH);

		Label gravityLabel = new Label("Gravity x:");
		final TextField gravityXText = new TextField(String.valueOf(world
				.getGravity().getX()), 4);
		buttonPosY += buttonH + buttonGap;
		gravityLabel.setBounds(initOffsetX, buttonPosY, buttonW/5*4, buttonH);
		gravityXText.setBounds(initOffsetX + buttonW / 5 * 4, buttonPosY,
				buttonW / 2, buttonH);
		Label gravityYLabel = new Label("y:");
		final TextField gravityYText = new TextField(String.valueOf(world
				.getGravity().getY()), 4);
		gravityYLabel.setBounds(initOffsetX + buttonW / 6 * 8, buttonPosY,
				buttonW / 4, buttonH);
		gravityYText.setBounds(initOffsetX + buttonW + buttonW/12*7, buttonPosY,
				buttonW / 2, buttonH);
		
		
		
		////// show FPS //////
		fpsLabel = new Label("FPS : ");
		buttonPosY += buttonH *2;
		fpsLabel.setBounds(initOffsetX, buttonPosY, buttonW*2, buttonH);
		
		
		
		////// show PROPERTIES/////
		Label proVertNumLabel = new Label("Vert. Num: ");
		buttonPosY += buttonH + buttonGap;
		proVertNumLabel.setBounds(initOffsetX, buttonPosY, buttonW*3, buttonH);
		propertyLabels.add(proVertNumLabel);
		
		Label proCenterLabel = new Label("Center Of Mass: ");
		buttonPosY += buttonH + buttonGap;
		proCenterLabel.setBounds(initOffsetX, buttonPosY, buttonW*3, buttonH);
		propertyLabels.add(proCenterLabel);
		
		Label proLinvel = new Label("Linear Vel: ");
		buttonPosY += buttonH + buttonGap;
		proLinvel.setBounds(initOffsetX, buttonPosY, buttonW*3, buttonH);
		propertyLabels.add( proLinvel);
		
		Label proAngVel = new Label("Angular Vel: ");
		buttonPosY += buttonH + buttonGap;
		proAngVel.setBounds(initOffsetX, buttonPosY, buttonW*3, buttonH);
		propertyLabels.add( proAngVel);
		
		
		
		
	

		/*
		 * add events to the menu
		 */
		loadButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				world.setPlaying(false);

				FileDialog fileOpen = new FileDialog(frame, "Open a JSON file",
						FileDialog.LOAD);
				fileOpen.setVisible(true);
				String loadPath = fileOpen.getDirectory() + fileOpen.getFile();

				if (loadPath.isEmpty()) {
					System.out.println("no File selected");
					return;
				}
				File file = new File(loadPath);
				try {
					FileReader reader = new FileReader(file);
					JSONTokener jsonTokener = new JSONTokener(reader);
					JSONObject jsonObject = new JSONObject(jsonTokener);
					// world.reset();
					world.setBodies(loadBody(jsonObject));
					// world.setPlaying(true);
					gravityXText.setText(String.valueOf(world.getGravity()
							.getX()));
					gravityYText.setText(String.valueOf(world.getGravity()
							.getY()));
					////ground
					//TODO ground
					/*
					Vector<Vec2> vertices = new Vector<Vec2>(); 
					 vertices.addElement(new Vec2(0, 0));
					 vertices.addElement(new Vec2(800, 0));
					 vertices.addElement(new Vec2(800, 20));
					 vertices.addElement(new Vec2(0, 20)); 
					 Body body = new
					 Body(true, 0f, 9f, new Vec2(0, 0), 0f,
					 2f, 0.5f, (List<Vec2>) vertices); world.addBody(body);
					 */
					 ////ground
				} catch (Exception exc) {
					exc.printStackTrace();
				}
			}
		});
		saveButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				world.setPlaying(false);
				FileDialog fileOpen = new FileDialog(frame,
						"Save a JSON file as...", FileDialog.SAVE);
				fileOpen.setFile("undefined.json");
				fileOpen.setVisible(true);
				String fileName = fileOpen.getDirectory() + fileOpen.getFile();
				if (fileName.isEmpty()) {
					System.out.println("Saving Path is Empty");
				}
				saveBody(world.getBodies(), fileName);
				world.setPlaying(true);
			}
		});

		playButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				world.setPlaying(true);
			}
		});

		pauseButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				world.setPlaying(false);
			}
		});

		// //////////////////free Draw Button/////////////////
		freeDrawButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				// TODO Auto-generated method stub
					world.setPlaying(false);
					setGenerateMode(false);
					setFreeDrawMode(true);
					tempBody = new TempBody();
				
			}
		});

		// ///// Whenever parameters are changed, set new body.
		for (int i = 0; i < bodyParamNames.length - 1; i++) {
			final String paramName = bodyParamNames[i];
			TextField f = bodyParamTexts.get(paramName);

			f.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					if (isGenerateMode) {
						if (paramName.equalsIgnoreCase("vertNum")) {
							tempBody = generateBodyFromParams(bodyParamTexts);
						} else {
							changeTempBody(bodyParamTexts, paramName, tempBody);
						}
					}
				}

			});
		}

		gravityXText.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String x = gravityXText.getText();
				try {
					world.setGravityX(Double.parseDouble(x));
					System.out.println("Gravity : " + world.getGravity());
				} catch (NumberFormatException e) {
					System.out.println("not available value");
					e.printStackTrace();
				}
			}
		});

		gravityYText.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String y = gravityYText.getText();
				try {
					world.setGravityY(Double.parseDouble(y));
					System.out.println("Gravity : " + world.getGravity());
				} catch (NumberFormatException e) {
					System.out.println("not available value");
					e.printStackTrace();
				}
			}
		});

		showButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				world.setPlaying(false);
				setFreeDrawMode(false);
				setGenerateMode(true);
				setTempBody(generateBodyFromParams(bodyParamTexts));

			}
		});

		cancelButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (isGenerateMode || isFreeDrawMode) {
					setTempBody(null);
					setFreeDrawMode(false);
					setGenerateMode(false);
					//world.setPlaying(true);
				}
			}
		});

		generateButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (isGenerateMode) {
					world.addBody(tempBody);
					setTempBody(null);
					setGenerateMode(false);
					// world.setPlaying(true);
				} else if (isFreeDrawMode) {
					
				}
			}
		});

		// //////add objects to panel /////
		menuPanel.add(loadButton);
		menuPanel.add(saveButton);
		menuPanel.add(playButton);
		menuPanel.add(pauseButton);
		menuPanel.add(clearButton);
		menuPanel.add(newBodyLabel);
		menuPanel.add(freeDrawButton);
		menuPanel.add(verticesNumLabel);
		menuPanel.add(verticesNumText);
		menuPanel.add(rotAngleLabel);
		menuPanel.add(rotAngleText);
		menuPanel.add(massLabel);
		menuPanel.add(massText);
		menuPanel.add(coefOfFrictionLabel);
		menuPanel.add(coefOfFrictionText);
		menuPanel.add(coefOfRestitutionLabel);
		menuPanel.add(coefOfRestitutionText);
		menuPanel.add(initLienarVelLabel);
		menuPanel.add(initLinVelXLabel);
		menuPanel.add(initLinVelYLabel);
		menuPanel.add(initLinVelXText);
		menuPanel.add(initLinVelYText);
		menuPanel.add(initAngVelLabel);
		menuPanel.add(initAngVelText);
		menuPanel.add(showButton);
		menuPanel.add(cancelButton);
		menuPanel.add(generateButton);
		menuPanel.add(envLabel);
		menuPanel.add(gravityLabel);
		menuPanel.add(gravityXText);
		menuPanel.add(gravityYLabel);
		menuPanel.add(gravityYText);
		menuPanel.add(fpsLabel);
		
		for (Label l : propertyLabels) menuPanel.add(l);

		frame.add(canvas);
		frame.add(menuPanel);
		frame.setResizable(false);
		frame.setVisible(true);

		// by default, an AWT Frame doesn't do anything when you click
		// the close button; this bit of code will terminate the program when
		// the window is asked to close
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				frame.dispose();
				System.exit(0);
			}
		});

		listener = new UIListener(this, world);
		// canvas.reshape(arg0, arg1, arg2, arg3)
		canvas.addGLEventListener(listener);
		canvas.addKeyListener(listener);
		canvas.addMouseListener(listener);
		canvas.addMouseMotionListener(listener);

		FPSAnimator animator = new FPSAnimator(canvas, 60);
		animator.add(canvas);
		animator.start();

	}

	public void update() {
		theta += 0.01;
		s = Math.sin(theta);
		c = Math.cos(theta);
		
		storedFrameRate.add(getFrameRate(lastFrameTime));
		if (storedFrameRate.size() >= 20) {
			double sum = 0.0;
			for (Double d : storedFrameRate) {
				sum += d;
			}
			DecimalFormat format = new DecimalFormat(".###");
			
			frameRate = sum / storedFrameRate.size();
			fpsLabel.setText("FPS : " + format.format(frameRate));
			storedFrameRate.clear();
		}
		
		setLastFrameTime(System.currentTimeMillis());
		
	}

	public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
		GL2 gl = drawable.getGL().getGL2();
		gl.glViewport(x, y, w, h);
	}

	public void render(GLAutoDrawable drawable, Vector<Body> bodies) {
		GL2 gl = drawable.getGL().getGL2();
		gl.glClear(GL.GL_COLOR_BUFFER_BIT);

		// draw a triangle filling the window
		gl.glBegin(GL.GL_LINE_LOOP);
		gl.glColor3f(1, 0, 0);
		gl.glVertex2d(-c, -c);
		gl.glColor3f(0, 1, 0);
		gl.glVertex2d(0, c);
		gl.glColor3f(0, 0, 1);
		gl.glVertex2d(s, -s);
		gl.glEnd();

		/*
		 * Body temp_body=new Body(); Vector<Vec2> temp_v = new Vector<Vec2>();
		 * 
		 * temp_body.position = new Vec2(200,200); temp_body.rotAngle =
		 * (float)Math.PI/3; temp_v.addElement(new Vec2(150,150));
		 * temp_v.addElement(new Vec2(150,250)); temp_v.addElement(new
		 * Vec2(250,250)); temp_v.addElement(new Vec2(250,150));
		 * temp_body.vertices = temp_v; drawABody(temp_body, gl);
		 */
		drawBody(bodies, gl);

		drawContact(world.arbiterList, gl);
		
		/*
		 * renderer.beginRendering(drawable.getWidth(), drawable.getHeight());
		 * 
		 * renderer.setColor(1.0f, 1f, 1f, 0.8f); renderer.draw("test", 0,
		 * drawable.getHeight()-36);
		 * 
		 * renderer.endRendering();
		 */
		if(selectedBody != null) drawProperty(selectedBody);
		
	}

	public void drawContact(Vector<Arbiter>arbiterList, GL2 gl){
		Vec2 cPoint;
		Vec2 v1, v2;
		for (int i=0; i<arbiterList.size();i++){
			for (int j=0;j<arbiterList.get(i).contacts.size();j++){
				cPoint = arbiterList.get(i).contacts.get(j).position;
				v1=arbiterList.get(i).contacts.get(j).sepAxisV1;
				v2=arbiterList.get(i).contacts.get(j).sepAxisV2;
				//System.out.println("contactpoint");
				//cPoint.print();
				gl.glPointSize(10.1f);
				gl.glBegin(GL.GL_POINTS);
				gl.glVertex2d(cPoint.getX() / 400 - 1, cPoint.getY() / 300 - 1);	
				//gl.glColor3f(1.0f, 1.0f, 1.0f);
				//gl.glVertex2d(v1.getX() / 400 - 1, v1.getY() / 300 - 1);
				//gl.glVertex2d(v2.getX() / 400 - 1, v2.getY() / 300 - 1);	
				gl.glColor3f(1.0f, 0f, 0f);
				gl.glEnd();
				
			}
		}
	}
	public void drawVertex(Body b, GL2 gl){
		Vec2 cPoint;
		if (b.isConvex) return;
		for (int i=0; i<b.subTriangles.size();i++){
			for (int j=0;j<b.subTriangles.get(i).getTvertices().size();j++){
				cPoint = b.subTriangles.get(i).getTvertices().get(j);
				cPoint = MyMath.rotation(cPoint, b.centerOfMass, b.rotAngle);
				//System.out.println("contactpoint");
				//cPoint.print();
				gl.glPointSize(10.1f);
				gl.glBegin(GL.GL_POINTS);
				gl.glVertex2d(cPoint.getX() / 400 - 1, cPoint.getY() / 300 - 1);		
				gl.glEnd();
				
			}
		}
	}
	public void drawBody(Vector<Body> bodyVec, GL2 gl) {
		int i;
		for (i = 0; i < bodyVec.size(); i++) {
			drawABody(bodyVec.get(i), gl);
			// drawVertex(bodyVec.get(i), gl);
		}

		if (isGenerateMode() || isFreeDrawMode()) {
			drawATempBody(tempBody, gl);
			// System.out.println(tempBody);
		}
	}
	

	private void drawATempBody(TempBody tempBody, GL2 gl) {

		if (isFreeDrawMode) {
			int i;
			gl.glColor3f(0, 1, 0);
			gl.glBegin(GL.GL_LINE_STRIP);
			for (i = 0; i < tempBody.vertices.size(); i++) {
				// temp = MyMath.rotation(tempBody.vertices.get(i),
				// tempBody.centerOfMass, tempBody.rotAngle);
				gl.glVertex2d(tempBody.vertices.get(i).getX() / 400 - 1, tempBody.vertices.get(i).getY() / 300 - 1);
			}
			gl.glEnd();
		} else {
			int i;
			gl.glColor3f(0, 1, 0);
			gl.glBegin(GL.GL_LINE_LOOP);
			Vec2 temp;
			for (i = 0; i < tempBody.vertices.size(); i++) {
				// temp = MyMath.rotation(tempBody.vertices.get(i),
				// tempBody.centerOfMass, tempBody.rotAngle);

				temp = MyMath.rotation(tempBody.vertices.get(i),
						tempBody.centerOfMass, tempBody.rotAngle);
				gl.glVertex2d(temp.getX() / 400 - 1, temp.getY() / 300 - 1);
			}
			gl.glEnd();
			gl.glPointSize(10.0f);
			gl.glBegin(GL.GL_POINTS);

			for (i = 0; i < tempBody.vertices.size(); i++) {
				// temp = MyMath.rotation(tempBody.vertices.get(i),
				// tempBody.centerOfMass, tempBody.rotAngle);
				temp = MyMath.rotation(tempBody.vertices.get(i),
						tempBody.centerOfMass, tempBody.rotAngle);
				gl.glVertex2d(temp.getX() / 400 - 1, temp.getY() / 300 - 1);
			}
			gl.glEnd();
		}
	}

	private void drawABody(Body body, GL2 gl) {

		//drawACircle(body, gl, true);
		//drawACircle(body, gl, false);
		int i;
		Vec2 temp;
		gl.glBegin(GL.GL_LINE_LOOP);
		if (body == selectedBody ) gl.glColor3f(1.0f, 1.0f, 0.0f);
		else gl.glColor3f(1, 0, 0);
		for (i = 0; i < body.vertices.size(); i++) {
			temp = MyMath.rotation(body.vertices.get(i), body.centerOfMass,
					body.rotAngle);

			// System.out.println("i = " +i +
			// " x="+temp.getX()+" y="+temp.getY());
			gl.glVertex2d(temp.getX() / 400 - 1, temp.getY() / 300 - 1);
		}

		gl.glEnd();
	}

	private void drawACircle(Body body, GL2 gl, boolean drawBody) {
		SubTriangle t;
		if (body.isEnv)
			return;
		for (int i = 0; i < body.subTriangles.size(); i++) {
			t = body.subTriangles.get(i);
			// Making circle in 50 small triangles
			double increment = 2 * Math.PI / 50;
			// Defining center of circle at (150, 150)
			double cx;
			if (drawBody)
				cx = body.centerOfMass.getX();
			else
				cx = MyMath.rotation(t.com, body.centerOfMass,body.rotAngle).getX();
			double cy;
			if (drawBody)
				cy = body.centerOfMass.getY();
			else
				cy = MyMath.rotation(t.com, body.centerOfMass,body.rotAngle).getY();
			// Defining radius of circle equal to 70 pixels
			double radius;
			if (drawBody)
				radius = body.radius;
			else
				radius = t.radiusOfBoundingCircle;
			// Starting loop for drawing triangles
			for (double angle = 0; angle < 2 * Math.PI; angle += increment) {
				gl.glBegin(GL.GL_LINE_LOOP);
				//gl.glColor3f(0, 0, 1);
				// We want to draw circle in blue colour
				if (drawBody==true)gl.glColor4f(0, 0, 1, 1);
				if (drawBody==false)gl.glColor4f(0, 0.7f, 0, 1);
				// One vertex of each triangle is at center of circle
				gl.glVertex2d(cx / 400 - 1, cy / 300 - 1);
				// Other two vertices form the periphery of the circle
				gl.glVertex2d(
						(cx + Math.cos(angle + increment) * radius) / 400 - 1,
						(cy + Math.sin(angle + increment) * radius) / 300 - 1);
				gl.glVertex2d((cx + Math.cos(angle) * radius) / 400 - 1,
						(cy + Math.sin(angle) * radius) / 300 - 1);
				gl.glEnd();
			}
		}
	}

	public void DrawText(int x, int y, String s) {

	}
		
	private void drawProperty(Body b) {
		///Env? or Moving Object?
		/*
		boolean isEnv;
		///Given Parameters
		float mass; //m>0
		Vec2 vel;
		float angularVelocity;
		float friction; //friction coefficient
		float e; // collision coefficient

		///Automatically set
		float rotAngle; //radian 	
		///Parameters Computed
		Vec2 force; //net force
		float torque; //net torque for the center of mass
		Vec2 centerOfMass;
		float I; //rotational inertia
		boolean isConvex;
		Vec2 centerOfBoundary; // center of bounding circle
		float radius; // radius bounding circle
		
		*/
		//propertyLabel

		DecimalFormat format = new DecimalFormat(".##");
		
		for (int i = 0 ; i < propertyLabels.size(); i++) {
			Label l = propertyLabels.get(i);
			String str;
			switch (i) {
			case 0: str = "Vert. Num: " + b.vertices.size();
			break;  
			case 1: str = "Center Of Mass:\n" + format.format(b.centerOfMass.getX()) + ", " + format.format(b.centerOfMass.getY()) ;
			break;
			case 2: str ="Linear Vel.:\n" + format.format(b.vel.getX()) + ", " 
					+ format.format(b.vel.getY());
			break;
			default: str = "Angular Vel.: " + format.format(b.angularVelocity);
			}
			l.setText(str);
		}		
	}

	@SuppressWarnings("unchecked")
	public void saveBody(Vector<Body> bodies, String filePath) {

		try {
			ArrayList<JSONObject> realBodies = new ArrayList<JSONObject>();
			ArrayList<JSONObject> obstacles = new ArrayList<JSONObject>();
			for (Body b : bodies) {
				@SuppressWarnings("rawtypes")
				HashMap bodySpec = new HashMap();
				bodySpec.put("rotAngle", b.rotAngle);
				bodySpec.put("mass", b.mass);
				bodySpec.put("linearVel", b.vel.getVecArr());
				bodySpec.put("angularVel", b.angularVelocity);
				bodySpec.put("coeOfFric", b.friction);
				bodySpec.put("coeOfRest", b.e);

				ArrayList<ArrayList<Double>> vertexArr = new ArrayList<ArrayList<Double>>();
				for (Vec2 v : b.vertices) {
					vertexArr.add(v.getVecArr());
				}
				bodySpec.put("vertices", vertexArr);
				JSONObject bodyObj = new JSONObject(bodySpec);
				if (b.isEnv)
					obstacles.add(bodyObj);
				else
					realBodies.add(bodyObj);
			}
			JSONArray bodiesJsonArr = new JSONArray(realBodies);
			JSONArray obstacleJsonArr = new JSONArray(obstacles);

			JSONObject envJson = new JSONObject();
			envJson.put("gravity", world.getGravity().getVecArr());
			envJson.put("obstacles", obstacleJsonArr);

			JSONObject jsonObj = new JSONObject();
			jsonObj.put("bodies", bodiesJsonArr);
			jsonObj.put("env", envJson);

			FileWriter fw = new FileWriter(new File(filePath));
			jsonObj.write(fw);
			fw.flush();
			fw.close();

		} catch (Exception exc) {
			exc.printStackTrace();
		}
	}

	private double getFrameRate (long lastFrameTime) {
		long elapsedTime =  System.currentTimeMillis() - lastFrameTime;
		
		double frameRate = 1000.0 / (double) elapsedTime;
		
		this.elapsedTime = elapsedTime;
		return frameRate;
	}
	
	private void setLastFrameTime(long curTime) {
		lastFrameTime = curTime;
	}
	
	private Vector<Vec2> generateVertices(int num, Vec2 center, double radius) {
		Vector<Vec2> verts = new Vector<Vec2>();
		double thetaOffset = (Math.PI * 2) / num;
		for (int i = 0; i < num; i++) {
			double x = center.getX() + radius
					* Math.cos(Math.PI * 2 - thetaOffset * i);
			double y = center.getY() + radius
					* Math.sin(Math.PI * 2 - thetaOffset * i);
			verts.add(new Vec2(x, y));
		}
		return verts;
	}


	private TempBody generateBodyFromParams(HashMap<String, TextField> params) {

		float rotangle = Float.parseFloat(params.get("rotAngle").getText());
		float mass = Float.parseFloat(params.get("mass").getText());
		double velX = Double.parseDouble(params.get("linearVelX").getText());
		double velY = Double.parseDouble(params.get("linearVelY").getText());
		Vec2 vel = new Vec2(velX, velY);
		float angVel = Float.parseFloat(params.get("angularVel").getText());
		float friction = Float.parseFloat(params.get("coeOfFric").getText());
		float e = Float.parseFloat(params.get("coeOfRest").getText());
		Vector<Vec2> vertices = generateVertices(Integer.parseInt(params.get(
				"vertNum").getText()), new Vec2(MyMath.random(0, 800), MyMath.random(0, 600)), 20.);
		TempBody newBody = new TempBody(false, rotangle, mass, vel, angVel,
				friction, e, vertices);
		System.out.println("-- show New Body --");
		System.out.println(newBody);
		return newBody;
	}

	private TempBody generateBodyFromParamsWithVertices(
			HashMap<String, TextField> params, List<Vec2> vertices) {
		float rotangle = Float.parseFloat(params.get("rotAngle").getText());
		float mass = Float.parseFloat(params.get("mass").getText());
		double velX = Double.parseDouble(params.get("linearVelX").getText());
		double velY = Double.parseDouble(params.get("linearVelY").getText());
		Vec2 vel = new Vec2(velX, velY);
		float angVel = Float.parseFloat(params.get("angularVel").getText());
		float friction = Float.parseFloat(params.get("coeOfFric").getText());
		float e = Float.parseFloat(params.get("coeOfRest").getText());
		TempBody newBody = new TempBody(false, rotangle, mass, vel, angVel,
				friction, e, vertices);
		return newBody;
	}

	private void changeTempBody(HashMap<String, TextField> params,
			String paramName, Body tempBody) {
		if (paramName.equals("vertNum")) {
			return;
		} else if (paramName.equals("linearVelX")) {
			tempBody.vel.setX(Double.parseDouble(params.get(paramName)
					.getText()));
			;
		} else if (paramName.equals("linearVelY")) {
			tempBody.vel.setY(Double.parseDouble(params.get(paramName)
					.getText()));
			;
		} else {

			float value = Float.parseFloat(params.get(paramName).getText());
			if (paramName.equalsIgnoreCase("rotAngle"))
				tempBody.rotAngle = value;
			else if (paramName.equalsIgnoreCase("mass"))
				tempBody.mass = value;
			else if (paramName.equalsIgnoreCase("coeOfFric"))
				tempBody.friction = value;
			else if (paramName.equalsIgnoreCase("coeOfRest"))
				tempBody.e = value;
			else if (paramName.equalsIgnoreCase("angularVel"))
				tempBody.angularVelocity = value;
		}
	}

	private Body generateBodyFromJson(JSONObject bodyData, boolean isEnv) {

		try {
			float rotAngle = (float) bodyData.getDouble("rotAngle");
			float mass = (float) bodyData.getDouble("mass");
			JSONArray velArr = bodyData.getJSONArray("linearVel");
			Vec2 vel = new Vec2(velArr.getDouble(0), velArr.getDouble(1));
			float angVel = (float) bodyData.getDouble("angularVel");
			float friction = (float) bodyData.getDouble("coeOfFric");
			float e = (float) bodyData.getDouble("coeOfRest");
			JSONArray vertArr = bodyData.getJSONArray("vertices");
			Vector<Vec2> vertices = new Vector<Vec2>();
			for (int j = 0; j < vertArr.length(); j++) {
				JSONArray vertex = vertArr.getJSONArray(j);
				vertices.add(new Vec2(vertex.getDouble(0), vertex.getDouble(1)));
			}
			return new Body(isEnv, rotAngle, mass, vel, angVel, friction, e,
					vertices);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public Vector<Body> loadBody(JSONObject json) {
		Vector<Body> bodies = new Vector<Body>();
		try {
			JSONArray jsonBodies = json.getJSONArray("bodies");
			for (int i = 0; i < jsonBodies.length(); i++) {
				JSONObject bodyData = jsonBodies.getJSONObject(i);
				Body body = generateBodyFromJson(bodyData, false);
				if (body == null)
					continue;

				bodies.add(body);
			}

			JSONObject jsonEnv = json.getJSONObject("env");
			JSONArray gravArr = jsonEnv.getJSONArray("gravity");
			Vec2 gravity = new Vec2(gravArr.getDouble(0), gravArr.getDouble(1));

			JSONArray jsonObstacles = jsonEnv.getJSONArray("obstacles");

			for (int i = 0; i < jsonObstacles.length(); i++) {
				JSONObject bodyData = jsonObstacles.getJSONObject(i);
				Body body = generateBodyFromJson(bodyData, true);
				if (body == null)
					continue;
				System.out.println("Obstacles : " + body);
				bodies.add(body);
			}
			System.out.println(bodies);
			world.setGravity(gravity);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return bodies;
	}

	public Body getTempBody() {
		return tempBody;
	}

	public void setTempBody(TempBody tempBody) {
		this.tempBody = tempBody;
	}

	public boolean isGenerateMode() {
		return isGenerateMode;
	}

	public void setGenerateMode(boolean isGenerateMode) {
		this.isGenerateMode = isGenerateMode;
	}

	public boolean isFreeDrawMode() {
		return isFreeDrawMode;
	}

	public void setFreeDrawMode(boolean isFreeDrawMode) {
		this.isFreeDrawMode = isFreeDrawMode;
	}

	private class TempBody extends Body {
		private boolean isCursorIn;
		private int selectedNum = -1;
		private boolean isSelected = false;

		public TempBody() {
			super();
			isEnv = false;
			rotAngle = 0.0f;
			mass = 0.0f;
			vel = new Vec2(0, 0);
			angularVelocity = 0;
			friction = 0;
			e = 0;

			vertices = new Vector<Vec2>();
			isCursorIn = false;
		}

		public TempBody(boolean env, float rotangle, float mass, Vec2 vel,
				float angVel, float friction, float e, List<Vec2> vertices) {
			super(false, rotangle, mass, vel, angVel, friction, e, vertices);
			isCursorIn = false;
		}



		public int checkWhichVertSelected(int mouseX, int mouseY) {
			int index = -1;
			double epsilon = 100.0;
			double minDist = Double.MAX_VALUE;
			for (int i = 0; i < vertices.size(); i++) {
				Vec2 temp = MyMath.rotation(vertices.get(i), centerOfMass,
						tempBody.rotAngle);

				Vec2 distVec = Vec2.minus(temp, new Vec2(mouseX, mouseY));
				double distSq = distVec.getX() * distVec.getX()
						+ distVec.getY() * distVec.getY();
				if (distSq <= epsilon && distSq < minDist) {
					minDist = distSq;
					index = i;
				}
			}

			return index;
		}

		private void reset() {
			float maxRadius = 0, tempRadius;
			// computing center of mass
			centerOfMass = calculateCenterOfMass();

			// determine convex
			isConvex = testConvex();

			// compute tessellation.*** it should be done whether it is convex
			// or not.
			subTriangles = new Vector<SubTriangle>();
			ITriangulationAlgorithm power = new EarClippingTriangulator();
			triangleTessellator(power.computeTriangles(vertices));

			// computing rotational inertia
			I = calculateRotationalInertia();

			// computing center of bounding circle & radius
			for (int i = 0; i < this.vertices.size(); i++) {
				tempRadius = (float) Math
						.sqrt(Math.pow(
								vertices.get(i).getX() - centerOfMass.getX(), 2)
								+ Math.pow(vertices.get(i).getY()
										- centerOfMass.getY(), 2));
				if (maxRadius < tempRadius) {
					maxRadius = tempRadius;
				}
			}
			this.radius = maxRadius;
		}
		

		public void moveVertex(int pmouseX, int pmouseY, int mouseX, int mouseY) {
			Vec2 v = vertices.get(selectedNum);
			Vec2 distVec = new Vec2(mouseX - pmouseX, mouseY - pmouseY);

			Vec2 temp = MyMath.rotation(distVec, new Vec2(0, 0), -rotAngle);
			v.set(v.getX() + temp.getX(), v.getY() + temp.getY());
			reset();
		}

		public void moveBody(int pmouseX, int pmouseY, int mouseX, int mouseY) {
			Vec2 distVec = new Vec2(mouseX - pmouseX, mouseY - pmouseY);

			for (Vec2 v : vertices) {
				v.set(v.getX() + distVec.getX(), v.getY() + distVec.getY());
			}

			reset();
		}

		public boolean isCursorIn() {
			return isCursorIn;
		}

		public void setCursorIn(boolean isCursorIn) {
			this.isCursorIn = isCursorIn;
		}

		public int getSelectedNum() {
			return selectedNum;
		}

		public void setSelectedNum(int selectedNum) {
			this.selectedNum = selectedNum;
		}
		
		public void recalVertices() {
			Vector<Vec2> tempVertices = new Vector<Vec2>();
			
			Vec2 lastVert = null;
			for (int i = 0 ; i < vertices.size(); i++) {
				Vec2 thisVert = vertices.get(i);
				if (i==0) {
					tempVertices.add(thisVert);
					lastVert = thisVert;
 				} else {
 					if (Vec2.distance(lastVert, thisVert) >= 20.0) {
 						tempVertices.add(thisVert);
 						lastVert = thisVert;
 					}
 				}
			}

			vertices = tempVertices;
			
		}
		
	}
	
	private class UIListener implements GLEventListener, KeyListener,
			MouseMotionListener, MouseListener {
		private int pmouseX, pmouseY;
		private UIController controller;
		private World world;

		public UIListener(UIController controller, World world) {
			this.controller = controller;
			this.world = world;
		}

		@Override
		public void mouseClicked(MouseEvent e) {
			// TODO Auto-generated method stub
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mouseExited(MouseEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void mousePressed(MouseEvent e) {
			if (controller.isGenerateMode) {
				int mouseX = e.getX();
				int mouseY = UIController.WINDOW_HEIGHT - e.getY();

				int chosenVert = tempBody
						.checkWhichVertSelected(mouseX, mouseY);
				if (chosenVert >= 0) {
					tempBody.selectedNum = chosenVert;
					pmouseX = mouseX;
					pmouseY = mouseY;
				}

				else if (tempBody.isCursorIn(mouseX, mouseY)) {
					tempBody.isSelected = true;
					pmouseX = mouseX;
					pmouseY = mouseY;
				}
			} else if (controller.isFreeDrawMode) {
				int mouseX = e.getX();
				int mouseY = UIController.WINDOW_HEIGHT - e.getY();
			
				tempBody.vertices.add(new Vec2(mouseX, mouseY));
				pmouseX = mouseX;
				pmouseY = mouseY;
			}
		}

		@Override
		public void mouseReleased(MouseEvent arg0) {
			// TODO Auto-generated method stub
			if (controller.isGenerateMode) {
				if (tempBody.selectedNum >= 0) {
					tempBody.reset();
					tempBody.selectedNum = -1;
				}
				if (tempBody.isSelected)
					tempBody.isSelected = false;
			} else if (controller.isFreeDrawMode()) {
				System.out.println("vert size is : " + tempBody.vertices.size());
				controller.setFreeDrawMode(false);
				controller.setGenerateMode(true);
				tempBody.recalVertices();
				tempBody = controller.generateBodyFromParamsWithVertices(controller.bodyParamTexts, tempBody.vertices);
		
			}
		}

		@Override
		public void mouseDragged(MouseEvent e) {
			if (controller.isGenerateMode) {
				int mouseX = e.getX();
				int mouseY = UIController.WINDOW_HEIGHT - e.getY();
				if (tempBody.selectedNum >= 0) {
					tempBody.moveVertex(pmouseX, pmouseY, mouseX, mouseY);
					pmouseX = mouseX;
					pmouseY = mouseY;
				} else if (tempBody.isSelected) {
					tempBody.moveBody(pmouseX, pmouseY, mouseX, mouseY);
					pmouseX = mouseX;
					pmouseY = mouseY;
				}
			} else if (controller.isFreeDrawMode) {
				int mouseX = e.getX();
				int mouseY = UIController.WINDOW_HEIGHT - e.getY();
				
				int distSq = (mouseX - pmouseX) * (mouseX - pmouseX) + (mouseY - pmouseY) * (mouseY - pmouseY);
				int epsilon = 4;
				if (distSq > epsilon) tempBody.vertices.add(new Vec2(mouseX, mouseY));
			}
		}

		@Override
		public void mouseMoved(MouseEvent e) {

			if (controller.isGenerateMode) {
				if (tempBody.isCursorIn(e.getX(), UIController.WINDOW_HEIGHT
						- e.getY())) {
					// System.out.println("is in");
				}
			}
			
			
			for (Body b : world.getBodies()){
				if (b.isCursorIn(e.getX(), UIController.WINDOW_HEIGHT - e.getY())){
					if (!b.isEnv) controller.selectedBody = b;
				}
			}
		}

		@Override
		public void keyPressed(KeyEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void keyReleased(KeyEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void keyTyped(KeyEvent arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void display(GLAutoDrawable drawable) {
			// TODO Auto-generated method stub
			float dt = 1/60f;//(float) elapsedTime / 1000.0f;
			controller.update();
			
			world.Step(dt);
			controller.render(drawable, world.getBodies());
			// reshape(drawable,0,0,800,600);
		}

		@Override
		public void dispose(GLAutoDrawable arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void init(GLAutoDrawable arg0) {
			// TODO Auto-generated method stub

		}

		@Override
		public void reshape(GLAutoDrawable drawable, int x, int y, int w,
				int h) {
			// TODO Auto-generated method stub
			controller.reshape(drawable, x, y, w, h);
		}

	}
}
